package com.ncmmall.querychannel.service;

import com.ncmmall.querychannel.JpaQueryUnwrap;
import com.ncmmall.querychannel.QueryPage;
import com.ncmmall.querychannel.QueryPageRequest;
import com.ncmmall.querychannel.QueryRepository;
import com.mysema.query.types.OrderSpecifier;
import com.mysema.query.types.Predicate;
import org.hibernate.SQLQuery;
import org.hibernate.transform.Transformers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.persistence.Query;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author linxs
 * 查询通道类
 * <p>
 * find* 为查询JPA对象
 * query* 为使用原生SQL查询JPA对象
 * select* 为使用原生SQL查询非JPA对象
 */
public abstract class AbstractQueryChannelService {

    private Logger logger = LoggerFactory.getLogger(getClass());

    public abstract QueryRepository getQueryRepository();

    private <T> JpaQueryUnwrap unwrapToBean(final String sql, final Class<T> clazz) {
        JpaQueryUnwrap unwrap = new JpaQueryUnwrap() {
            @Override
            public void execute(Query query) {
                query.unwrap(SQLQuery.class).setResultTransformer(Transformers.aliasToBean(clazz));
            }
        };
        return unwrap;
    }

    private JpaQueryUnwrap unwrapToMap() {
        JpaQueryUnwrap unwrap = new JpaQueryUnwrap() {
            @Override
            public void execute(Query query) {
                query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
            }
        };
        return unwrap;
    }

    // ======================= 查询JPA对象 ===================//

    /**
     * @param clazz
     * @param primaryKey
     * @param <T>
     * @return
     */
    public <T> T findOne(Class<T> clazz, Object primaryKey) {
        try {
            return getQueryRepository().findOne(clazz, primaryKey);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * @param sql
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> T findOne(String sql, Class<T> clazz) {

        try {
            return getQueryRepository().findOne(sql, new HashMap<String, Object>(), clazz);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * @param queryString
     * @param params
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> T findOne(String queryString, Map<String, Object> params, Class<T> clazz) {
        return getQueryRepository().findOne(queryString, params, clazz);
    }

    /**
     * @param predicate
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> T findOne(Predicate predicate, Class<T> clazz) {
        return this.getQueryRepository().findOne(predicate, clazz);
    }

    public <T> T findFirst(String sql, Map<String, Object> params, Class<T> clazz) {
        try {
            return getQueryRepository().findFirst(sql, params, clazz);

        } catch (Exception e) {
            return null;
        }
    }

    /**
     * @param limit
     * @param count
     * @param queryString
     * @param params
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> List<T> findAll(int limit, int count, String queryString, Map<String, Object> params, Class<T> clazz) {
        return getQueryRepository().findAll(limit, count, queryString, params, clazz);
    }

    /**
     * @param queryString
     * @param params
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> List<T> findAll(String queryString, Map<String, Object> params, Class<T> clazz) {
        return getQueryRepository().findAll(queryString, params, clazz);
    }

    /**
     * @param queryString
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> List<T> findAll(String queryString, Class<T> clazz) {
        return getQueryRepository().findAll(queryString, new HashMap<>(), clazz);
    }

    /**
     * @param queryString
     * @param pageRequest
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> QueryPage<T> findPage(String queryString, QueryPageRequest pageRequest, Class<T> clazz) {
        return getQueryRepository().findPage(queryString, pageRequest, clazz);
    }

    /**
     * @param queryString
     * @param pageRequest
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> List<T> findLimit(String queryString, QueryPageRequest pageRequest, Class<T> clazz) {
        return getQueryRepository().findLimit(queryString, pageRequest, clazz);
    }

    /**
     * @param predicate
     * @param orders
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> List<T> findAll(Predicate predicate, OrderSpecifier<?>[] orders, Class<T> clazz) {
        return this.getQueryRepository().findAll(predicate, orders, clazz);
    }

    /**
     * @param predicate
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> List<T> findAll(Predicate predicate, Class<T> clazz) {
        return this.getQueryRepository().findAll(predicate, clazz);
    }

    /**
     * @param predicate
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> Long findCount(Predicate predicate, Class<T> clazz) {
        return this.getQueryRepository().findCount(predicate, clazz);
    }


    // =============================原生SQL查询=======================//

    /**
     * @param sql
     * @param params
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> T selectOneDTO(String sql, Map<String, Object> params, Class<T> clazz) {
        try {
            JpaQueryUnwrap unwrap = unwrapToBean(sql, clazz);
            return getQueryRepository().selectOneDTO(sql, params, unwrap);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * @param sql
     * @param params
     * @return
     */
    public Map<String, Object> selectOneMap(String sql, Map<String, Object> params) {
        try {
            JpaQueryUnwrap unwrap = unwrapToMap();
            return getQueryRepository().selectOneMap(sql, params, unwrap);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * @param sql
     * @param params
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> List<T> selectAllDTO(String sql, Map<String, Object> params, Class<T> clazz) {
        JpaQueryUnwrap unwrap = unwrapToBean(sql, clazz);
        return getQueryRepository().selectAllDTO(sql, params, unwrap);
    }

    /**
     * @param sql
     * @param params
     * @param unwrap
     * @param <T>
     * @return
     */
    public <T> List<T> selectAllDTO(String sql, Map<String, Object> params, JpaQueryUnwrap unwrap) {
        return getQueryRepository().selectAllDTO(sql, params, unwrap);
    }

    /**
     * @param sql
     * @param pageRequest
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> List<T> selectLimitDTO(String sql, QueryPageRequest pageRequest, Class<T> clazz) {
        JpaQueryUnwrap unwrap = unwrapToBean(sql, clazz);
        return getQueryRepository().selectLimitDTO(sql, pageRequest, unwrap);
    }

    /**
     * @param sql
     * @param params
     * @return
     */
    public List<Map<String, Object>> selectAllMap(String sql, Map<String, Object> params) {
        JpaQueryUnwrap unwrap = unwrapToMap();
        return getQueryRepository().selectAllMap(sql, params, unwrap);
    }

    /**
     * @param sql
     * @param pageRequest
     * @param <T>
     * @return
     */
    public <T> QueryPage<T> selectPageMap(String sql, QueryPageRequest pageRequest) {
        JpaQueryUnwrap unwrap = unwrapToMap();
        return getQueryRepository().selectPageDTO(sql, pageRequest, unwrap);
    }

    /**
     * @param sql
     * @param pageRequest
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> QueryPage<T> selectPageDTO(String sql, QueryPageRequest pageRequest, Class<T> clazz) {
        JpaQueryUnwrap unwrap = unwrapToBean(sql, clazz);
        return getQueryRepository().selectPageDTO(sql, pageRequest, unwrap);
    }

    /**
     * @param sql
     * @param pageRequest
     * @param unwrap
     * @param <T>
     * @return
     */
    public <T> QueryPage<T> selectPageDTO(String sql, QueryPageRequest pageRequest, JpaQueryUnwrap unwrap) {
        return getQueryRepository().selectPageDTO(sql, pageRequest, unwrap);
    }

    /**
     * @param sql
     * @param params
     * @return
     */
    public int selectCount(String sql, Map<String, Object> params) {
        return getQueryRepository().selectCount(sql, params);
    }

    public double selectSum(String sql, Map<String, Object> params) {
        return getQueryRepository().selectSum(sql, params);

    }

    /**
     * 原生sql平均值查询
     *
     * @param sql
     * @param params
     * @return
     */
    public double selectAvg(String sql, Map<String, Object> params) {
        return getQueryRepository().selectAvg(sql, params);
    }

    //=============================原生SQL 实体类查询 ====================//

    /**
     * @param sql
     * @param pageRequest
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> List<T> queryLimitEntity(String sql, QueryPageRequest pageRequest, Class<T> clazz) {
        return getQueryRepository().queryLimitEntity(sql, pageRequest, clazz);
    }

    /**
     * @param sql
     * @param params
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> List<T> queryAllEntity(String sql, Map<String, Object> params, Class<T> clazz) {
        return getQueryRepository().queryAllEntity(sql, params, clazz);
    }

    /**
     * @param sql
     * @param params
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> T queryOneEntity(String sql, Map<String, Object> params, Class<T> clazz) {
        try {
            return getQueryRepository().queryOneEntity(sql, params, clazz);
        } catch (Exception exception) {
            return null;
        }
    }

    /**
     * @param sql
     * @param pageRequest
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> QueryPage<T> queryPageEntity(String sql, QueryPageRequest pageRequest, Class<T> clazz) {
        return getQueryRepository().queryPageEntity(sql, pageRequest, clazz);
    }

}
